﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;

namespace DataHandlerService
{
    public partial class DataHandlerService : Form
    {
        int rcvDataPtr = -1;
        byte[] rcvData = null;

        uint rcvdDataType = 0;

        ProgressBars.ProgBarsHdl progbar;

        public delegate string GetOMXCompName(uint compId);
        public delegate void PostInfoMessage(string info);

        GetOMXCompName getOMXCompNameFunc = null;
        PostInfoMessage postInfo = null;

        #region data reception message ids and statuses
        uint msgReceiveID = 0;
        uint statDataSetUp = 0;
        uint statDataFull = 0;
        uint statDataStart = 0;
        uint statDataMore = 0;
        uint statDataEnd = 0;
        uint dataTypeJpeg = 0;
        uint dataTypeInfo = 0;
        #endregion

        #region communication object delegates and reference
        CommLink.CommLink commObject;
        CommLink.CommLink.MessageReceived dataRcvDelegate;
        CommLink.CommLink.ConnectionStatusEvent connectionStatusDelegate;
        #endregion

        #region constructors
        void commonConstructorCode(CommLink.CommLink iCommObject)
        {
            InitializeComponent();

            dataRcvDelegate = new CommLink.CommLink.MessageReceived(commObject_OnMessageReceived);
            connectionStatusDelegate = new CommLink.CommLink.ConnectionStatusEvent(commObject_OnConnectionStatusEvent);

            commObject = iCommObject;
            commObject.OnMessageReceived += dataRcvDelegate;
            commObject.OnConnectionStatusEvent += connectionStatusDelegate;
        }

        public DataHandlerService(CommLink.CommLink iCommObject, GetOMXCompName iGetCompName, PostInfoMessage iPostInfo)
        {
            commonConstructorCode(iCommObject);

            getOMXCompNameFunc = iGetCompName;

            postInfo = iPostInfo;
        }
        #endregion

        #region destructors
        void commObjDetach()
        {
            commObject.OnMessageReceived -= dataRcvDelegate;
            commObject.OnConnectionStatusEvent -= connectionStatusDelegate;
        }

        ~DataHandlerService()
        {
            commObjDetach();
        }
        #endregion

        public void SetDataCommIds(uint rcvId, uint setUp, uint full, uint start, uint more, uint end, uint JpegId, uint InfoId)
        {
            msgReceiveID = rcvId;
            statDataSetUp = setUp;
            statDataFull = full;
            statDataStart = start;
            statDataMore = more;
            statDataEnd = end;
            dataTypeJpeg = JpegId;
            dataTypeInfo = InfoId;
        }

        int read4BytesSigned(ref int bytePtr, byte[] byteArr)
        {
            int tmp = 0;
            for (int i = 0; i < 4; i++)
                tmp |= byteArr[bytePtr++] << (i*8);
            return tmp;
        }

        uint read4BytesUnsigned(ref int bytePtr, byte[] byteArr)
        {
            uint tmp = 0;
            for (int i = 0; i < 4; i++)
                tmp |= (uint)(byteArr[bytePtr++] << (i * 8));
            return tmp;
        }
        
        #region auto-saving jpeg images with incremental names
        
        const string IMAGES_DIR = "\\images";

        void autoSaveIncImage()
        {
            FileInfo nImgFile = null;
            DirectoryInfo selDir = null;
            DirectoryInfo dirImages = new DirectoryInfo(Application.StartupPath + IMAGES_DIR);
            if (!dirImages.Exists)
                dirImages.Create();

            DirectoryInfo[] dirSubImgs = dirImages.GetDirectories();

            string todayDir = DateTime.Now.Date.ToShortDateString();
            todayDir = todayDir.Replace('/', '.');

            for(int i = 0; i < dirSubImgs.Length; i++)
            {
                if(dirSubImgs[i].Name == todayDir)
                {
                    selDir = dirSubImgs[i];
                    break;
                }
            }

            if(selDir == null)
            {
                selDir = new DirectoryInfo(dirImages.FullName + "\\" + todayDir);
                if (!selDir.Exists)
                {
                    selDir.Create();
                }
            }
            
            FileInfo[] imgFiles = selDir.GetFiles();

            int res = 0;
            
            int CheckValue = 0;

            for(int k = 0; k < imgFiles.Length; k++)
            {
                if (int.TryParse(imgFiles[k].Name.Substring(0, imgFiles[k].Name.Length - 5), out CheckValue))
                {
                    if(CheckValue > res)
                        res = CheckValue;
                }
            }
            res++;
            nImgFile = new FileInfo(selDir.FullName + "\\" + res + ".jpeg");

            if(nImgFile != null)
            {
                BinaryWriter bw = new BinaryWriter(nImgFile.Create());
                bw.Write(rcvData);
                bw.Close();
            }
        }
        #endregion

        void commObject_OnMessageReceived(byte[] msgData)
        {
            int msgDataPtr = 0;

            uint msgId = read4BytesUnsigned(ref msgDataPtr, msgData);
            uint msgStat = read4BytesUnsigned(ref msgDataPtr, msgData);
            uint msgSize = read4BytesUnsigned(ref msgDataPtr, msgData);
           
            if (msgId == msgReceiveID)
            {
                if (msgStat == statDataSetUp)
                {
                    if (rcvData != null && rcvDataPtr > -1 && rcvdDataType == dataTypeJpeg)
                    {
                        autoSaveIncImage();
                    }

                    if (msgSize != 16)
                    {
                        MessageBox.Show("Invalid data set up message size.\nDiscarding message data");
                        rcvData = null;
                        rcvDataPtr = 1;

                        if (progbar != null)
                        {
                            progBarDisp.DestroyProgressBar(progbar);
                            progbar = null;
                        }
                    }
                    else
                    {
                        uint compId = read4BytesUnsigned(ref msgDataPtr, msgData);
                        uint compPort = read4BytesUnsigned(ref msgDataPtr, msgData);
                        rcvdDataType = read4BytesUnsigned(ref msgDataPtr, msgData);
                        uint dataSize = read4BytesUnsigned(ref msgDataPtr, msgData);

                        rcvData = new byte[dataSize];
                        rcvDataPtr = 0;

                        progbar = progBarDisp.CreateProgressBar(dataSize + " bytes from " + getOMXCompNameFunc(compId) + " on port " + compPort.ToString());
                        progbar.SetMinimum(0);
                        progbar.SetMaximum((int)dataSize);
                        progbar.SetStep(1);
                    }
                }
                else if (msgStat == statDataFull || msgStat == statDataStart || msgStat == statDataMore || msgStat == statDataEnd)
                {
                    if (rcvData != null && rcvDataPtr > -1)
                    {
                        uint dataCpy = msgSize;
                        if (rcvDataPtr + msgSize > rcvData.Length)
                        {
                            MessageBox.Show("Receive data larger than accepted in set up message.\nClipping to set-up size.");
                            dataCpy = (uint)(rcvData.Length - rcvDataPtr);
                        }

                        while (msgDataPtr < dataCpy + 12)
                        {
                            rcvData[rcvDataPtr++] = msgData[msgDataPtr++];
                            progbar.Step();
                        }

                        if (msgStat == statDataFull || msgStat == statDataEnd)
                        {
                            progBarDisp.DestroyProgressBar(progbar);
                            progbar = null;
                            if (rcvdDataType == dataTypeJpeg)
                            {
                                try
                                {
                                    picBoxMain.Image = new Bitmap(new MemoryStream(rcvData));
                                }
                                catch
                                {
                                    MessageBox.Show("Errors getting image from bytestream!");
                                }
                            }
                            else if (rcvdDataType == dataTypeInfo)
                            {
                                if (postInfo != null)
                                {
                                    char[] argh = new char[rcvData.Length];
                                    for (int i = 0; i < rcvData.Length; i++)
                                    {
                                        argh[i] = (char)rcvData[i];
                                    }
                                    string strIn = new string(argh);
                                    postInfo(strIn);
                                }
                            }
                        }
                    }
                }
                else
                {
                    MessageBox.Show("Unrecognized data status.\nDiscarding message data");
                    rcvData = null;
                    rcvDataPtr = 1;
                }
            }
        }

        void commObject_OnConnectionStatusEvent(CommLink.CommLinkAbstract.ConnectionStates eState)
        {
            if (eState != CommLink.CommLinkAbstract.ConnectionStates.Connected)
            {
                commObjDetach();
                MessageBox.Show("Communication error");
                DialogResult = DialogResult.Abort;
            }
        }

        private void bntSave_Click(object sender, EventArgs e)
        {
            if (rcvData != null)
            {
                SaveFileDialog sfd = new SaveFileDialog();
                if (sfd.ShowDialog() == DialogResult.OK)
                {
                    BinaryWriter bw = new BinaryWriter((new FileInfo(sfd.FileName)).Create());
                    bw.Write(rcvData);
                    bw.Close();
                }
            }
        }

        private void btnCancel_Click(object sender, EventArgs e)
        {
            DialogResult = DialogResult.Cancel;
        }

        private void btnJPEG_Click(object sender, EventArgs e)
        {
            if (rcvData != null)
            {
                try
                {
                    picBoxMain.Image = new Bitmap(new MemoryStream(rcvData));
                    picBoxMain.Size = new Size(picBoxMain.Image.Width, picBoxMain.Image.Height);
                }
                catch{}
            }
        }
    }
}
